import React, {
  ReactNode,
  AnchorHTMLAttributes,
  ButtonHTMLAttributes,
  PropsWithChildren,
  useMemo,
} from 'react'
import styled from 'styled-components'
import { color, typography } from '../shared/styles'
import { darken, rgba, opacify } from 'polished'
import { easing } from '../shared/animation'

export type AppearancesTypes = keyof typeof APPEARANCES

type btnType =
  | 'primary'
  | 'primaryOutline'
  | 'secondary'
  | 'secondaryOutline'
  | 'tertiary'
  | 'outline'
  | 'inversePrimary'
  | 'inverseSecondary'
  | 'inverseOutline'

type AppearancesObj = {
  [key in btnType]: btnType
}

export const APPEARANCES: AppearancesObj = {
  primary: 'primary',
  primaryOutline: 'primaryOutline',
  secondary: 'secondary',
  secondaryOutline: 'secondaryOutline',
  tertiary: 'tertiary',
  outline: 'outline',
  inversePrimary: 'inversePrimary',
  inverseSecondary: 'inverseSecondary',
  inverseOutline: 'inverseOutline',
}

type sizeType = 'small' | 'medium'
type sizeObj = {
  [key in sizeType]: sizeType
}

export const SIZES: sizeObj = {
  small: 'small',
  medium: 'medium',
}

export type SizesTypes = keyof typeof SIZES

export const btnPadding = {
  small: '8px 16px',
  medium: '13px 20px',
}

const Text = styled.span`
  display: inline-block;
  vertical-align: top;
`

const Loading = styled.span`
  position: absolute;
  top: 50%;
  left: 0;
  right: 0;
  opacity: 0;
`

// 对传入接口进行定义
export interface CustormButtonProps {
  /** 是否禁用 */
  disabled?: boolean
  /** 是否加载中 */
  isLoading?: boolean
  /** 是否是a标签 */
  isLink?: boolean
  /** 是否替换加载中文本 */
  loadingText?: ReactNode
  /** 按钮大小 */
  size?: SizesTypes
  /** 按钮类型 */
  appearance?: AppearancesTypes
  /** 无效点击 */
  isUnclickable?: boolean
}

export type ButtonProps = CustormButtonProps &
  AnchorHTMLAttributes<HTMLAnchorElement> &
  ButtonHTMLAttributes<HTMLButtonElement>

const StyledButton = styled.button<ButtonProps>`
  border: 0;
  border-radius: 3em;
  cursor: pointer;
  display: inline-block;
  overflow: hidden;
  padding: ${(props) =>
    props.size === SIZES.small ? btnPadding.small : btnPadding.medium};
  position: relative;
  text-align: center;
  text-decoration: none;
  transition: all 150ms ease-out;
  transform: translate3d(0,0,0);
  vertical-align: top;
  white-space: nowrap;
  user-select: none;
  opacity: 1;
  margin: 0;
  background: transparent;
  font-size: ${(props) =>
    props.size === SIZES.small ? typography.size.s1 : typography.size.s2}px;
  font-weight: ${typography.weight.extrabold};
  line-height: 1;
  ${(props) =>
    !props.isLoading &&
    `
      &:hover {
        transform: translate3d(0, -2px, 0);
        box-shadow: rgba(0, 0, 0, 0.2) 0 2px 6px 0;
      }
      &:active {
        transform: translate3d(0, 0, 0);
      }
      &:focus {
        box-shadow: ${rgba(color.primary, 0.4)} 0 1px 9px 2px;
        outline: none;
      }
      &:focus:hover {
        box-shadow: ${rgba(color.primary, 0.2)} 0 8px 18px 0px;
      }
    `}
  ${Text} {
    transform: scale3d(1,1,1) translate3d(0,0,0);
    transition: transform 700ms ${easing.rubber};
    opacity: 1;
  }
  ${Loading} {
    transform: translate3d(0, 100%, 0);
  }
  ${(props) =>
    props.disabled &&
    `
      cursor: not-allowed !important;
      opacity: 0.5;
      &:hover {
        transform: none;
      }
    `}
  ${(props) =>
    props.isUnclickable &&
    `
      cursor: default !important;
      pointer-events: none;
      &:hover {
        transform: none;
      }
    `}
  ${(props) =>
    props.isLoading &&
    `
      cursor: progress !important;
      opacity: 0.7;
      ${Loading} {
        transition: transform 700ms ${easing.rubber};
        transform: translate3d(0, -50%, 0);
        opacity: 1;
      }
      ${Text} {
        transform: scale3d(0, 0, 1) translate3d(0, -100%, 0);
        opacity: 0;
      }
      &:hover {
        transform: none;
      }
    `}
  ${(props) =>
    props.appearance === APPEARANCES.primary &&
    `
      background: ${color.primary};
      color: ${color.lightest};
      ${
        !props.isLoading &&
        `
          &:hover {
            background: ${darken(0.05, color.primary)};
          }
          &:active {
            box-shadow: rgba(0, 0, 0, 0.1) 0 0 0 3em inset;
          }
          &:focus {
            box-shadow: ${rgba(color.primary, 0.4)} 0 1px 9px 2px;
          }
          &:focus:hover {
            box-shadow: ${rgba(color.primary, 0.2)} 0 8px 18px 0px;
          }
        `
      }
    `}
  ${(props) =>
    props.appearance === APPEARANCES.secondary &&
    `
      background: ${color.secondary};
      color: ${color.lightest};
      ${
        !props.isLoading &&
        `
          &:hover {
            background: ${darken(0.05, color.secondary)};
          }
          &:active {
            box-shadow: rgba(0, 0, 0, 0.1) 0 0 0 3em inset;
          }
          &:focus {
            box-shadow: ${rgba(color.secondary, 0.4)} 0 1px 9px 2px;
          }
          &:focus:hover {
            box-shadow: ${rgba(color.secondary, 0.2)} 0 8px 18px 0px;
          }
        `
      }
    `}
  ${(props) =>
    props.appearance === APPEARANCES.tertiary &&
    `
      background: ${color.tertiary};
      color: ${color.darkest};
      ${
        !props.isLoading &&
        `
          &:hover {
            background: ${darken(0.05, color.tertiary)};
          }
          &:active {
            box-shadow: rgba(0, 0, 0, 0.1) 0 0 0 3em inset;
          }
          &:focus {
            box-shadow: ${rgba(color.darkest, 0.15)} 0 1px 9px 2px;
          }
          &:focus:hover {
            box-shadow: ${rgba(color.darkest, 0.05)} 0 8px 18px 0px;
          }
        `
      }
    `}
  ${(props) =>
    props.appearance === APPEARANCES.outline &&
    `
      box-shadow: ${opacify(0.05, color.border)} 0 0 0 1px inset;
      color: ${color.dark};
      background: transparent;
      ${
        !props.isLoading &&
        `
          &:hover {
            box-shadow: ${opacify(0.3, color.border)} 0 0 0 1px inset;
          }
          &:active {
            background: ${opacify(0.05, color.border)};
            box-shadow: transparent 0 0 0 1px inset;
            color: ${color.darkest};
          }
          &:active:focus:hover {
            ${
              /* This prevents the semi-transparent border from appearing atop the background */ ''
            }
            background: ${opacify(0.05, color.border)};
            box-shadow:  ${rgba(color.darkest, 0.15)} 0 1px 9px 2px;
          }
          &:focus {
            box-shadow: ${opacify(0.05, color.border)} 0 0 0 1px inset, 
            ${rgba(color.darkest, 0.15)} 0 1px 9px 2px;
          }
          &:focus:hover {
            box-shadow: ${opacify(0.05, color.border)} 0 0 0 1px inset, 
            ${rgba(color.darkest, 0.05)} 0 8px 18px 0px;
          }
        `
      };
    `};
    ${(props) =>
      props.appearance === APPEARANCES.primaryOutline &&
      `
        box-shadow: ${color.primary} 0 0 0 1px inset;
        color: ${color.primary};
        &:hover {
          box-shadow: ${color.primary} 0 0 0 1px inset;
          background: transparent;
        }
        &:active {
          background: ${color.primary};
          box-shadow: ${color.primary} 0 0 0 1px inset;
          color: ${color.lightest};
        }
        &:focus {
          box-shadow: ${color.primary} 0 0 0 1px inset, ${rgba(
        color.primary,
        0.4
      )} 0 1px 9px 2px;
        }
        &:focus:hover {
          box-shadow: ${color.primary} 0 0 0 1px inset, ${rgba(
        color.primary,
        0.2
      )} 0 8px 18px 0px;
        }
      `};
    ${(props) =>
      props.appearance === APPEARANCES.secondaryOutline &&
      `
        box-shadow: ${color.secondary} 0 0 0 1px inset;
        color: ${color.secondary};
        &:hover {
          box-shadow: ${color.secondary} 0 0 0 1px inset;
          background: transparent;
        }
        &:active {
          background: ${color.secondary};
          box-shadow: ${color.secondary} 0 0 0 1px inset;
          color: ${color.lightest};
        }
        &:focus {
          box-shadow: ${color.secondary} 0 0 0 1px inset,
            ${rgba(color.secondary, 0.4)} 0 1px 9px 2px;
        }
        &:focus:hover {
          box-shadow: ${color.secondary} 0 0 0 1px inset,
            ${rgba(color.secondary, 0.2)} 0 8px 18px 0px;
        }
      `};
      ${(props) =>
        props.appearance === APPEARANCES.inversePrimary &&
        `
          background: ${color.lightest};
          color: ${color.primary};
          ${
            !props.isLoading &&
            `
              &:hover {
                background: ${color.lightest};
              }
              &:active {
                box-shadow: rgba(0, 0, 0, 0.1) 0 0 0 3em inset;
              }
              &:focus {
                box-shadow: ${rgba(color.primary, 0.4)} 0 1px 9px 2px;
              }
              &:focus:hover {
                box-shadow: ${rgba(color.primary, 0.2)} 0 8px 18px 0px;
              }
          `
          }
      `}
      ${(props) =>
        props.appearance === APPEARANCES.inverseSecondary &&
        `
          background: ${color.lightest};
          color: ${color.secondary};
          ${
            !props.isLoading &&
            `
              &:hover {
                background: ${color.lightest};
              }
              &:active {
                box-shadow: rgba(0, 0, 0, 0.1) 0 0 0 3em inset;
              }
              &:focus {
                box-shadow: ${rgba(color.secondary, 0.4)} 0 1px 9px 2px;
              }
              &:focus:hover {
                box-shadow: ${rgba(color.secondary, 0.2)} 0 8px 18px 0px;
              }
          `
          }
      `}
      ${(props) =>
        props.appearance === APPEARANCES.inverseOutline &&
        `
          box-shadow: ${color.lightest} 0 0 0 1px inset;
          color: ${color.lightest};
          &:hover {
            box-shadow: ${color.lightest} 0 0 0 1px inset;
            background: transparent;
          }
          &:active {
            background: ${color.lightest};
            box-shadow: ${color.lightest} 0 0 0 1px inset;
            color: ${color.darkest};
          }
          &:focus {
            box-shadow: ${color.lightest} 0 0 0 1px inset,
              ${rgba(color.darkest, 0.4)} 0 1px 9px 2px;
          }
          &:focus:hover {
            box-shadow: ${color.lightest} 0 0 0 1px inset,
              ${rgba(color.darkest, 0.2)} 0 8px 18px 0px;
          }
      `};
`

export function Button(props: PropsWithChildren<ButtonProps>) {
  const { isLoading, loadingText, isLink, children } = props
  const buttonInner = (
    <>
      <Text>{children}</Text>
      {isLoading && <Loading>{loadingText || 'Loading...'}</Loading>}
    </>
  )
  const btnType = useMemo(() => {
    if (isLink) {
      return 'a'
    }
  }, [isLink])

  return (
    <StyledButton as={btnType} {...props}>
      {buttonInner}
    </StyledButton>
  )
}

Button.defaultProps = {
  isLoading: false,
  loadingText: null,
  isLink: false,
  appearance: APPEARANCES.tertiary,
  isDisabled: false,
  isUnclickable: false,
  containsIcon: false,
  size: SIZES.medium,
  ButtonWrapper: undefined,
}
